package ch.ethz.fcl.metrobuzz.data.accessibility.activity;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import org.newdawn.slick.util.ResourceLoader;

import au.com.bytecode.opencsv.CSVReader;
import ch.ethz.fcl.metrobuzz.algorithm.network.shortest_path.public_transport.Walk;
import ch.ethz.fcl.metrobuzz.data.MBData;
import ch.ethz.fcl.metrobuzz.data.transit.Stop;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Polygon;
import diewald_shapeFile.files.dbf.DBF_File;
import diewald_shapeFile.files.shp.SHP_File;
import diewald_shapeFile.files.shp.shapeTypes.ShpPoint;
import diewald_shapeFile.files.shx.SHX_File;
import diewald_shapeFile.shapeFile.ShapeFile;

public class POIReaderWritter {
	public static List<PointOfInterest> readFromWrittenFile(MBData data,
			String fileName) {
		List<PointOfInterest> pois = new ArrayList<PointOfInterest>();

		try {
			InputStreamReader isr = new InputStreamReader(
					ResourceLoader.getResourceAsStream(fileName));
			BufferedReader br = new BufferedReader(isr);
			String s = null;
			while ((s = br.readLine()) != null) {
				PointOfInterest poi = new PointOfInterest();

				String[] xy = s.split("\t");
				float x = Float.parseFloat(xy[1].split(":")[1]);
				float y = Float.parseFloat(xy[2].split(":")[1]);

				poi.setPosition(x, y);

				s = br.readLine();
				String[] nearbyStops = s.split("\t");
				for (int i = 1; i < nearbyStops.length; i++) {
					String[] stops = nearbyStops[i].split(":");
					String stopId = stops[0];
					Stop stop = data.getPublicTransit().getStopByNodeId(stopId);

					if (stop == null)
						continue;

					float walkCost = Float.parseFloat(stops[1]);

					poi.addNearbyStop(stop);
					poi.addStopWalkCost(stop, walkCost);
				}

				pois.add(poi);
				br.readLine();
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		return pois;
	}

	public static List<PointOfInterest> readFromCSVFile(MBData data,
			String fileName) {
		List<PointOfInterest> pois = new ArrayList<PointOfInterest>();
		try {
			CSVReader csvReader = new CSVReader(new FileReader(fileName));
			List<String[]> content = csvReader.readAll();

			for (int i = 1; i < content.size(); i++) {
				String[] row = content.get(i);

				String x = row[1];
				String y = row[2];

				PointOfInterest poi = new PointOfInterest();

				float boundX = data.getScene().getBound()
						.normalizeX(Float.parseFloat(x));
				float boundY = data.getScene().getBound()
						.normalizeY(Float.parseFloat(y));
				poi.setPosition(boundX, boundY);

				// check if the activity is on land
				boolean onLand = false;
				for (Polygon zone : data.getSGInfo().getSGZones()
						.getSingaporeZone())
					if (zone.contains(boundX, boundY)) {
						onLand = true;
						break;
					}

				if (onLand) {
					for (Stop stop : data.getPublicTransit().getStops()) {
						float walkCost = Walk.walkCost(data, stop.toPoint(),
								poi.toPoint());
						// within 10 minutes walk
						if (walkCost <= Walk.MAXIMUM_WALK_LIMIT)
							poi.addNearbyStop(stop);
					}
					pois.add(poi);
				}
			}

			for (PointOfInterest work : pois) {
				for (Stop stop : work.getNearbyStops())
					work.addStopWalkCost(stop,
							Walk.walkCost(data, stop.toPoint(), work.toPoint()));
			}

			csvReader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return pois;
	}

	public static List<PointOfInterest> readFromShapeFile(MBData data,
			String folderName, String fileName) {
		DBF_File.LOG_INFO = false;
		DBF_File.LOG_ONLOAD_HEADER = false;
		DBF_File.LOG_ONLOAD_CONTENT = false;

		SHX_File.LOG_INFO = false;
		SHX_File.LOG_ONLOAD_HEADER = false;
		SHX_File.LOG_ONLOAD_CONTENT = false;

		SHP_File.LOG_INFO = false;
		SHP_File.LOG_ONLOAD_HEADER = false;
		SHP_File.LOG_ONLOAD_CONTENT = false;

		List<PointOfInterest> pois = new ArrayList<PointOfInterest>();

		try {
			ShapeFile shapefile = new ShapeFile(folderName, fileName).READ();

			int number_of_shapes = shapefile.getSHP_shapeCount();

			for (int i = 0; i < number_of_shapes; i++) {
				ShpPoint point = shapefile.getSHP_shape(i);

				PointOfInterest poi = new PointOfInterest();

				float[] coord = Transverse_Mercator_TO_UTM84_48N(
						(float) point.getPoint()[0],
						(float) point.getPoint()[1]);

				float boundX = data.getScene().getBound().normalizeX(coord[0]);
				float boundY = data.getScene().getBound().normalizeY(coord[1]);
				poi.setPosition(boundX, boundY);

				for (Stop stop : data.getPublicTransit().getStops()) {
					float walkCost = Walk.walkCost(data, stop.toPoint(),
							poi.toPoint());

					if (walkCost <= Walk.MAXIMUM_WALK_LIMIT) {
						poi.addNearbyStop(stop);
						poi.addStopWalkCost(stop, walkCost);
					}
				}

				pois.add(poi);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return pois;
	}

	public static void saveToFile(MBData data, List<PointOfInterest> pois,
			String fileName) {
		try {
			FileWriter fw = new FileWriter(fileName);

			for (int i = 0; i < pois.size(); i++) {
				PointOfInterest work = pois.get(i);
				fw.write(i + "\t");
				fw.write("x:" + work.getX() + "\t" + "y:" + work.getY() + "\n");

				fw.write("Nearbystops:walkCost\t");
				for (Stop nearbyStop : work.getNearbyStops()) {
					fw.write(nearbyStop.getId()
							+ ":"
							+ Walk.walkCost(data, nearbyStop.toPoint(),
									work.toPoint()) + "\t");
				}
				fw.write("\n\n");
			}

			fw.flush();
			fw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Projection: Transverse_Mercator False_Easting: 28001.642 False_Northing:
	 * 38744.572 Central_Meridian: 103.8333333333333 Scale_Factor: 1.0
	 * Latitude_Of_Origin: 1.366666666667 Linear Unit: Meter (1.0)
	 * 
	 * @param x
	 *            Transverse Mercator coordinate x
	 * @param y
	 *            Transverse Mercator coordinate y
	 * @return UTM 84 Zone 48N coordinates
	 */
	private static float[] Transverse_Mercator_TO_UTM84_48N(float x, float y) {
		float[] UTM84_48N_xy = new float[2];

		float False_Easting = 28001.642f, False_Northing = 38744.572f;

		// centroid coordinates in UTM84_48N_xy generated from lat/lon:
		// 1.366666667/103.8333333333
		float centroid_x = 370207f, centroid_y = 151090f;

		UTM84_48N_xy[0] = x - False_Easting + centroid_x;
		UTM84_48N_xy[1] = y - False_Northing + centroid_y;

		return UTM84_48N_xy;
	}
}
